package com.lagou.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Activate(group = {CommonConstants.PROVIDER})
public class TPMonitorFilter implements Filter {
    private static final int STATS_STANDARD_REQUESTS = 2000;

    public static final int TP90 = (int) (STATS_STANDARD_REQUESTS * 0.90);

    public static final int TP99 = (int) (STATS_STANDARD_REQUESTS * 0.99);

    private static LinkedList<TPWrapper> responseElapsedTimes = new LinkedList<>();

    public TPMonitorFilter() {
        /**
         * 打印TP90 TP99 当Response elapsed time size>2000的时候开始统计TP90 TP99
         */
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                if (responseElapsedTimes.size() >= STATS_STANDARD_REQUESTS) {
                    /**
                     * 按照消耗时间顺序排序
                     */
                    System.out.println("=========Response elapsed time size: " + responseElapsedTimes.size());
                    System.out.println("=========TP90:" + responseElapsedTimes.get(TP90).elapsed + " ms");
                    System.out.println("=========TP99:" + responseElapsedTimes.get(TP99).elapsed + " ms");
                } else {
                    System.out.println("=========Response elapsed time size: " + responseElapsedTimes.size());
                }
            }
        }, 5000, 5000, TimeUnit.MILLISECONDS);

    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

        long startTime = System.currentTimeMillis();
        try {
            // 执行方法
            return invoker.invoke(invocation);
        } finally {
            long elapsed = (System.currentTimeMillis() - startTime);
            recordElapsedTimes(elapsed);
        }
    }


    private synchronized void recordElapsedTimes(long elapsed) {
        if (responseElapsedTimes.size() == STATS_STANDARD_REQUESTS) {
            /**
             * 超过2000次记录后，按照消耗记录时间顺序排序，删除第一个记录
             */
            responseElapsedTimes.sort(Comparator.comparingLong(TPWrapper::getElapsed));
            responseElapsedTimes.removeFirst();
        }
        responseElapsedTimes.add(new TPWrapper(elapsed, System.currentTimeMillis()));
        /**
         * 按照消耗时间顺序排序
         */
        responseElapsedTimes.sort(Comparator.comparingLong(TPWrapper::getElapsed));

    }


    public static class TPWrapper {

        public long elapsed;

        public long recordTimestamp;

        public TPWrapper(long elapsed, long recordTimestamp) {
            this.elapsed = elapsed;
            this.recordTimestamp = recordTimestamp;
        }
        public long getElapsed() {
            return elapsed;
        }
    }
}
